package ar.edu.utn.frgp.Banco.service.impl;

import java.util.List;
import ar.edu.utn.frgp.Banco.dao.IClienteDao;
import ar.edu.utn.frgp.Banco.dao.ICuentaDao;
import ar.edu.utn.frgp.Banco.dao.IPagoServiciosDao;
import ar.edu.utn.frgp.Banco.dao.IPlazosFijosDao;
import ar.edu.utn.frgp.Banco.dao.IMovimientosDao;
import ar.edu.utn.frgp.Banco.dao.IServicioDao;
import ar.edu.utn.frgp.Banco.model.Cliente;
import ar.edu.utn.frgp.Banco.model.Cuenta;
import ar.edu.utn.frgp.Banco.model.Movimiento;
import ar.edu.utn.frgp.Banco.model.PagoServicios;
import ar.edu.utn.frgp.Banco.model.PlazoFijo;
import ar.edu.utn.frgp.Banco.model.Servicios;
import ar.edu.utn.frgp.Banco.model.enums.Estado;
import ar.edu.utn.frgp.Banco.model.enums.TipoCuenta;
import ar.edu.utn.frgp.Banco.service.BusinessException;
import ar.edu.utn.frgp.Banco.service.IRecursoService;

public class RecursoServiceImpl implements IRecursoService {

	private IClienteDao clienteDao;
	private ICuentaDao cuentaDao;
	private IPlazosFijosDao plazofijoDao;
	private IMovimientosDao movimientoDao;
	private IServicioDao serviciosDao;
	private IPagoServiciosDao pagoservicioDao;

	// Esta anotacion solo debemos usarla si usamos el transactionManager sin
	// AOP (AspectJ)
	// @Transactional

	// ////////////////////// CLIENTE
	public void crearCliente(Cliente cliente) throws BusinessException {

		if (clienteDao.getById(cliente) == null) // si no existe lo creo
		{
			cliente.setEstado(1);
			clienteDao.create(cliente);
		} else
			throw new BusinessException(
					"El cliente ya existe en la base de datos"); // lanzo la excepcion
		}

	public Cliente getCliente(String dni) {
		return null;
	}

	public IClienteDao getClienteDao() {
		return clienteDao;
	}

	public List<Cliente> getClientes() {
		return clienteDao.getAll();
	}

	public List<Cliente> getClientesActivos() {
		return clienteDao.getAllActivos();
	}

	public void setClienteDao(IClienteDao clienteDao) {
		this.clienteDao = clienteDao;
	}


	public void modificarCliente(Cliente cliente) throws BusinessException {
		
		try {
			Cliente clienteOriginal = clienteDao.getById(cliente);
			
			if(clienteOriginal.getEstado() == 0){
				throw new BusinessException("No se puede modificar un cliente que ha sido eliminado.");
			}
			cliente.setEstado(1);
			clienteDao.update(cliente);
			
		}catch (BusinessException busEx) {
			throw busEx;
		} 
		catch (Exception e) {
			throw new BusinessException("Se produjo un error al intentar modificar el cliente.");
		}
	}

	public void bajaCliente(Cliente cliente) throws BusinessException {
		Cliente clientebaja = new Cliente();
		clientebaja = clienteDao.getById(cliente);
		clientebaja.setEstado(0);
		clienteDao.update(clientebaja);
	}

	// //////////////////////// CUENTA
	public void crearCuenta(Cuenta cuenta) throws Exception {
		try {
			if (cuenta == null) {
				throw new BusinessException("La cuenta ingresada no es valida.");
			}
			if (cuenta.getTipo() == 0 && cuenta.getDescubierto() != 0) {
				throw new BusinessException(
						"Solo la Cuentas Corrientes pueden tener descubierto.");
			}

			if (cuenta.getSaldo() < 0) {
				throw new BusinessException(
						"El saldo de una cuenta no puede ser negativo.");
			}

			if (cuenta.getDni() == 0) {
				throw new BusinessException(
						"El ciente asociando a la cuenta no es valido.");
			}

			Cliente cliente = new Cliente();
			cliente.setDni(cuenta.getDni());
			cliente = clienteDao.getById(cliente);

			if (cliente == null) {
				throw new BusinessException("No se encontro al Cliente "
						+ cuenta.getDni() + " en la base de clientes.");
			}

			if (cliente.getEstado() == 0) {
				throw new BusinessException("El Cliente " + cliente.toString()
						+ " Se encuenta dado de Baja.");
			}
			cuentaDao.create(cuenta);

		} catch (BusinessException busEx) {
			throw busEx;
		} catch (Exception e) {
			throw new BusinessException(
					"Se produjo un error al intentar modificar la cuenta");
		}
	}

	public ICuentaDao getCuentaDao() {
		return cuentaDao;
	}

	public List<Cuenta> getCuentas() {
		return cuentaDao.getAll();
	}

	public void setCuentaDao(ICuentaDao cuentaDao) {
		this.cuentaDao = cuentaDao;
	}

	public void ActualizarSaldoCuenta(Cuenta cuenta) throws BusinessException {
		try {
			if (cuenta == null) {
				throw new BusinessException("La cuenta ingresada no es valida.");
			}

			Cuenta cuentaoriginal = cuentaDao.getById(cuenta);
			if (cuentaoriginal == null) {
				throw new BusinessException("No se encontro la cuenta.");
			}

			cuentaoriginal.setSaldo(cuentaoriginal.getSaldo() + cuenta.getSaldo());
			cuentaDao.update(cuentaoriginal);

		} catch (BusinessException busEx) {
			throw busEx;
		} catch (Exception e) {
			throw new BusinessException(
					"Se produjo un error al intentar altualizar el saldo de la cuenta.");
		}
	}

	public void modificarCuenta(Cuenta cuenta) throws BusinessException {
		try {
			if (cuenta == null) {
				throw new BusinessException("La cuenta ingresada no es valida.");
			}

			Cuenta cuentaoriginal = cuentaDao.getById(cuenta);
			if (cuentaoriginal == null) {
				throw new BusinessException("No se encontro la cuenta.");
			}

			if (cuenta.getTipo() == 0 && cuenta.getDescubierto() != 0) {
				throw new BusinessException(
						"Solo la Cuentas Corrientes pueden tener descubierto.");
			}
			
			if(cuentaoriginal.getEstado() == 0){
				throw new BusinessException("La cuenta " + cuentaoriginal.getNrocuenta() + " se encuentra dada de baja.");
			}

//			if (cuenta.getSaldo() < 0) {
//				throw new BusinessException(
//						"El saldo de una cuenta no puede ser negativo.");
//			}

			Cliente cliente = new Cliente();
			cliente.setDni(cuentaoriginal.getDni());
			cliente = clienteDao.getById(cliente);

			if (cliente == null) {
				throw new BusinessException("No se encontro al Cliente "
						+ cuenta.getDni() + " en la base de clientes.");
			}

			if (cliente.getEstado() == 0) {
				throw new BusinessException("El Cliente " + cliente.toString()
						+ " Se encuenta dado de Baja.");
			}

			cuentaoriginal.setTipo(cuenta.getTipo());
			cuentaoriginal.setDescubierto(cuenta.getDescubierto());
//			cuentaoriginal.setSaldo(cuenta.getSaldo());
			cuentaDao.update(cuentaoriginal);

		} catch (BusinessException busEx) {
			throw busEx;
		} catch (Exception e) {
			throw new BusinessException(
					"Se produjo un error al intentar modificar la cuenta");
		}
	}

	public void bajaCuenta(Cuenta cuenta) throws BusinessException {

		Cuenta cuentabaja = new Cuenta();
		cuentabaja = cuentaDao.getById(cuenta);

		cuentabaja.setEstado(0);
		cuentaDao.update(cuentabaja);
	}

	// ////////////////////////////// PLAZOS FIJO
	public void crearPlazoFijo(PlazoFijo plazofijo) throws Exception {
		try {
			Cuenta cuenta = new Cuenta();
			cuenta.setNrocuenta(plazofijo.getNrocuentaorigen());
			cuenta.setSaldo((plazofijo.getMonto() * -1));
			ActualizarSaldoCuenta(cuenta);
			plazofijoDao.create(plazofijo);
		} catch (BusinessException bs) {
			throw bs;
		} 
		catch (Exception e) {
			throw new BusinessException("Ocurrio un error al intentar crear el plazo fijo");
		}
		
	}

	public IPlazosFijosDao getPlazoFijoDao() {
		return plazofijoDao;
	}

	public List<PlazoFijo> getPlazoFijos() {
		return plazofijoDao.getAll();
	}

	public IPlazosFijosDao getPlazofijoDao() {
		return plazofijoDao;
	}

	public void setPlazofijoDao(IPlazosFijosDao plazofijoDao) {
		this.plazofijoDao = plazofijoDao;
	}

	// ////////////////////////////// Movimiento
	public IMovimientosDao getMovimientoDao() {
		return movimientoDao;
	}

	public List<Movimiento> getMovimientos() {
		return movimientoDao.getAll();
	}

	public IMovimientosDao getMovimientosDao() {
		return movimientoDao;
	}

	public void setMovimientoDao(IMovimientosDao movimientoDao) {
		this.movimientoDao = movimientoDao;
	}

	public void actualizarDescubierto(Cuenta cuenta, Double nuevoDescubierto)
			throws BusinessException {
		try {
			if (cuenta == null || cuenta.getNrocuenta() == 0) {
				throw new BusinessException("Cuenta invalidada");
			}

			if (nuevoDescubierto < 0) {
				throw new BusinessException(
						"El descubierto no puede ser negativo.");
			}

			if (cuenta.getTipo() != TipoCuenta.CUENTA_CORRIENTE.ordinal()) {
				throw new BusinessException(
						"Solo las Cuentas Corrientes pueden tener descubierto.");
			}

			Cuenta cuentaOriginal = getCuentaDao().getById(cuenta);
			if (cuentaOriginal == null) {
				throw new BusinessException("No se encontro la cuenta: "
						+ cuenta.getId());
			}

			if (cuentaOriginal.getEstado() == Estado.INHABILITADA.ordinal()) {
				throw new BusinessException("La cuenta: " + cuenta.getId()
						+ " se encuenta inhabilitada.");
			}

			cuentaOriginal.setDescubierto(nuevoDescubierto);
			getCuentaDao().update(cuentaOriginal);

		} catch (BusinessException busEx) {
			throw busEx;
		} catch (Exception e) {
			throw new BusinessException(
					"Se produjo un error no contemplado al intentar actualizar el descubierto.");
		}
	}

	// //////////////////////SERVICIO

	public List<Servicios> getServicios() {
		return getServiciosDao().getAll();
	}

	public IServicioDao getServiciosDao() {
		return serviciosDao;
	}

	public void setServiciosDao(IServicioDao serviciosDao) {
		this.serviciosDao = serviciosDao;
	}

	public void crearPagoServico(PagoServicios pagoservicio) throws Exception {

		try {
			Servicios servicio = new Servicios();
			servicio.setIdservicio(pagoservicio.getIdservicio());

			servicio = serviciosDao.getById(servicio);

			Cuenta cu = new Cuenta();
			cu.setNrocuenta(pagoservicio.getNrocuenta());
			cu.setSaldo(servicio.getMontofijo());
			cu.setSaldo(cu.getSaldo() * -1);
			ActualizarSaldoCuenta(cu);
			
			pagoservicioDao.create(pagoservicio);
		}
		catch (BusinessException be) {
			throw be;
		}
		catch (Exception e) {
			throw new BusinessException("Se produjo un error al intentar pagar un saldo.");
		}

	}

	public void ActualizarSaldoCuentaPorPagoServicio(PagoServicios pagoservicio) {
		Servicios servicio = new Servicios();
		// servicio.setId(String.valueOf(pagoservicio.getIdservicio()));
		servicio.setId(pagoservicio.getIdservicio());

		Servicios servicio1 = serviciosDao.getById(servicio);
		Cuenta cuenta = new Cuenta();
		cuenta.setNrocuenta(pagoservicio.getNrocuenta());
		Cuenta cuentaoriginal = cuentaDao.getById(cuenta);
		cuentaoriginal.setSaldo(cuentaoriginal.getSaldo()
				- servicio1.getMontofijo());
		cuentaDao.update(cuentaoriginal);
	}

	public IPagoServiciosDao getPagoservicioDao() {
		return pagoservicioDao;
	}

	public void setPagoservicioDao(IPagoServiciosDao pagoservicioDao) {
		this.pagoservicioDao = pagoservicioDao;
	}

	public List<PagoServicios> getPagoServicios() {
		return pagoservicioDao.getAll();
	}
		

	public void crearServicio(Servicios servicios) throws BusinessException {
		serviciosDao.create(servicios);
	}

}
